5

js构造函数

前言:之前看过公司大神的代码,发现有很多构造函数,类似Java和C#的 new 方法来实例化一个对象,感觉很是受教,刚好最近在用es6,发现了用class来实现构造函数,于是总结了一下,也是回顾和提高的过程,由于本人也是前端小白,文章可能有很多错误,欢迎各位大神批评指正~~

传统ES5语法

    // 常规方法一
    function Persion(name, age) {
        this.name = name;                // this.key 赋值,则直接挂载到Persion实例
        this.age = age;
        this.getInfo = function() {
            return {
                name: this.name,
                age: this.age
            }
        }
    }
    // 调用
    var persion = new Persion('张三', 15);
    // 此时的persion实例拥有name、age、getInfo()三个属性及方法

    // 常规方法二
    function Persion(name, age) {
        var name = name;
        var age = age;
        var getInfo = function() {
            return {
                name: name,
                age: age,
            }
        }
        return { // 通过return将元素暴露给实例对象
            name: name,
            age: age,
            getInfo: getInfo,
        }
    }
    // 调用 
    var persion = new Persion('张三', 15);
    // 此时的persion实例拥有name、age、getInfo()三个属性及方法

ES6

class Persion {
    constructor(name, age) { // 一个类必须有constructor方法, 如果没有显式定义, 一个空的constructor方法会被默认添加。
        this.name = name;
        this.age = age;
    }
    getInfo() {
        return {
            name: this.name,
            age: this.age,
        }
    }
}
// 调用
const persion = new Persion('张三', 17);
// 此时的persion实例拥有name、age、getInfo()三个属性及方法

注:ES6 class 声明构造函数会将所有内部元素暴露出来,但有的时候我们希望这些方法只在内部声明时使用,并不暴露给实例对象,在ES5中我们可以很方便的做到,如下栗子:

    // ES5 实现私有方法
    // 方案一
    function Persion(name, age) {
        this.name = name;
        this.age = age;
        var print = function(){
            return name + '今年' + age + '岁了!';
        }
        this.setName = function(newName){
            this.name = newName;
        }
        this.setAge = function(newAge){
            this.age = newAge;
        }
        this.getInfo = function(){
            {
                name: name,
                age: age,
            }
        }
        this.printInfo = function(){
            console.log(print());
        }
    }
    // 实例化
    var persion = newPersion('张三', 15);
    
    // 方案二
    function Persion(name, age) {
        var name = name,
            age = age;
        // print作为私有方法,只在内部用于生成输出字符串,并不需要暴露到外部
        var print = function(){
            return name + '今年' + age + '岁了!';
        }
        var setName = function(newName){
            name = newName;
        }
        var setAge = function(newAge){
            age = newAge;
        }
        var getInfo = function(){
            {
                name: name,
                age: age,
            }
        }
        var printInfo = function(){
            console.log(print());
        }
        return {
            name: name,
            age: age,
            setName: setName,
            setAge: setAge,
            getInfo: getInfo,
            printInfo: printInfo,
        }
    }
    // 实例化
    var persion = newPersion('张三', 15);
    // 此时实例化的persion 将不会暴露出print方法,我个人更倾向于方案二的方法,可以清楚的看出哪些属性和方法需要暴露出来,也容易修改需要暴露的接口。

那么在ES6中我们要怎么实现私有的方法和属性呢?其实方法很多,但都很不友好,我只总结了三种,如果有什么好的方法欢迎大家给我留言,不胜感激:)

// 私有方法 变通方案
// 方案一 (其实并不算一个方法。。。)
class Persion {
    constructor(name, age) { 
        this.name = name;
        this.age = age;
    }
    _print() { // 通常以“_”开头命名的方法为内部私有方法
        return name + '今年' + age + '岁了!';
    }
    setName(newName) {
        this.name = newName;
    }
    setName(newAge) {
        this.age= newAge;
    }
    printInfo() {
        console.log(_print());
    }
    getInfo() {
        return {
            name: this.name,
            name: this.age,
        }
    }
}
// 实例化
const persion = new Persion('张三', 15);
// 此时persion实例仍然能获取到_print方法,只能用来区分私用和公有方法而已;

// 方案二
// 注意若使用ES6箭头函数则this指向的是该方法本身,而非调用它的对象,
function _print() { // 外部声明_print 方法,在内部调用,此时_print 成为Persion类的私有方法
    return this.name + '今年' + this.age + '岁了!';
}
class Persion {
    constructor(name, age) { 
        this.name = name;
        this.age = age;
    }
    setName(newName) {
        this.name = newName;
    }
    setName(newAge) {
        this.age= newAge;
    }
    printInfo() {
        console.log(_print());
    }
    getInfo() {
        return {
            name: this.name,
            name: this.age,
        }
    }
}
// 实例化
const persion = new Persion('张三', 15);
// 此时persion实例获取不到_print方法;
    
// 方案三
const print = Symbol('print'); // 声明一个Symbol值,用来做为私有方法的名字
class Persion {
    constructor(name, age) { 
        this.name = name;
        this.age = age;
    }
    setName(newName) {
        this.name = newName;
    }
    setName(newAge) {
        this.age= newAge;
    }
    [bar]() {  // 将私有方法的名字命名为一个Symbol值。
        return this.name + '今年' + this.age + '岁了!';
    }
    printInfo() {
        console.log([bar]()); // 调用私有方法
    }
    getInfo() {
        return {
            name: this.name,
            name: this.age,
        }
    }
}
// 实例化
const persion = new Persion('张三', 15);
// 此时persion实例获取不到[bar]方法;

# 追更
感谢 @黒之染 的评论, 构造函数还可以通过prototype来添加对象

栗子:
```
function Persion(name, age){
    this.name = name,
    this.age = age,
}
Persion.prototype.getInfo = function(){
    return {
        name: this.name,
        age: this.name,
    }
}
// 实例化
var persion = new Persion('张三');
// 此时实例化后的对象persion拥有getInfo()方法
persion.getInfo() // 输出{name: '张三'}
```

关于js构造函数的继承可以看一下我的下一篇文章js构造函数(继承方法及利弊)


张吉成
49 声望3 粉丝